#!/bin/bash

function get_pcpu
{
    local pcpu
    pcpu=$[100-$(top -b -n 1 | sed -n '3p' | awk -F, '{print $4}' | awk '{print $1}' | awk -F. '{print $1+1}')]
    echo "$pcpu"
}

function help
{
    echo "Usage: pcpu.sh start|stop|show|help [options]"
    echo "start options:"
    echo -e "\tmin_pcpu: 最低cpu使用率 0~100范围内"
    echo -e "\tmax_pcpu: 最高cpu使用率 0~100范围内"
    echo -e "\trun_time: 运行时间, 单位默认为分钟"
    echo -e "\ttime_unit: 时间单位, 分钟 m 小时 h 天 d"
    echo -e "\tformat: pcpu.sh start min_pcpu max_pcpu run_time [time_unit]"
    echo -e "\texample: pcpu.sh start 60 70 10 m 维持cpu使用率在60%~70%, 持续10分钟"
    echo "stop options:"
    echo -e "\texample: pcpu.sh stop 强制停止"
    echo "show options:"
    echo -e "\tinterval_time: 间隔多久循环查看当前cpu使用率, 单位为秒 不传的话仅查看一次"
    echo -e "\tformat: pcpu.sh show [interval_time]"
    echo -e "\texample: pcpu.sh show 查看当前cpu使用率"
    echo "help options:"
    echo -e "\texample: pcpu.sh help 查看帮助信息"
}

function is_digit
{
    if [ $1 -eq 0 ];then
        return 1
    fi
    local res
    res=$(grep "^[1-9][0-9]*$" <<< "$1")
    if [ $res = "" ];then
        return 0
    else
        return 1
    fi
}



function start
{
    local min_pcpu
    min_pcpu=$1
    if [ "$min_pcpu" = "" ];then
        echo "Error: missing parameter min_pcpu"
        help
        exit 1
    fi
    is_digit "$min_pcpu"
    if [ $? -eq 0 ];then
        echo "Error: parameter min_pcpu is not a number"
        help
        exit 1
    fi
    if [[ $min_pcpu -lt 0 || $min_pcpu -gt 100 ]];then
        echo "Error: parameter min_pcpu must be between 0 and 100"
        help
        exit 1
    fi

    local max_pcpu
    max_pcpu=$2
    if [ "$max_pcpu" = "" ];then
        echo "Error: missing parameter max_pcpu"
        help
        exit 1
    fi
    is_digit "$max_pcpu"
    if [ $? -eq 0 ];then
        echo "Error: parameter max_pcpu is not a number"
        help
        exit 1
    fi
    if [[ $max_pcpu -lt 0 || $max_pcpu -gt 100 ]];then
        echo "Error: parameter max_pcpu must be between 0 and 100"
        help
        exit 1
    fi

    if [ $max_pcpu -le $min_pcpu ];then
        echo "Error: parameter max_pcpu must be greater than parameter min_pcpu"
        help
        exit 1
    fi

    local run_time
    run_time=$3
    if [ "$run_time" = "" ];then
        echo "Error: missing parameter run_time"
        help
        exit 1
    fi
    is_digit "$run_time"
    if [ $? -eq 0 ];then
        echo "Error: parameter run_time is not a number"
        help
        exit 1
    fi

    local stop_time
    case $4 in
        m)
            stop_time=$(date -d "+$run_time minute" +%s)
        ;;
        h)
            stop_time=$(date -d "+$run_time hour" +%s)
        ;;
        d)
            stop_time=$(date -d "+$run_time day" +%s)
        ;;
        *)
            stop_time=$(date -d "+$run_time minute" +%s)
        ;;
    esac


    local pid
    local more_pcpu
    local less_pcpu
    local current_cpu
    local kill_number
    local start_number
    while true
    do
        current_cpu=$(get_pcpu)
        if [ "$min_pcpu" -ge "$current_cpu" ];then
            less_pcpu=$[$min_pcpu - $current_cpu]
            if [ "$less_pcpu" -ge 0 ];then
                start_number=1
            fi
            if [ "$less_pcpu" -ge 5 ];then
                start_number=2
            fi
            if [ "$less_pcpu" -ge 10 ];then
                start_number=3
            fi
            if [ "$less_pcpu" -ge 15 ];then
                start_number=4
            fi
            for ((i=0;i<"$start_number";i++))
            do
                sha512sum /dev/zero &
            done
        fi
        if [ "$max_pcpu" -le "$current_cpu" ];then
            more_pcpu=$[$current_cpu - $max_pcpu]
            if [ "$more_pcpu" -ge 0 ];then
                kill_number=1
            fi
            if [ "$more_pcpu" -ge 5 ];then
                kill_number=2
            fi
            if [ "$more_pcpu" -ge 10 ];then
                kill_number=3
            fi
            if [ "$more_pcpu" -ge 15 ];then
                kill_number=4
            fi
            pid=$(ps -eo pid,cmd | grep "sha512sum /dev/zero" | grep "grep" -v | head -n "$kill_number" | awk '{print $1}')
            if [ ! -z "$pid" ]; then
                echo "$pid" | xargs kill -9
            fi
        fi
        if [ "$stop_time" -le "$(date +%s)" ];then
            break
        fi
        sleep 1
    done
    pid=$(ps -eo pid,cmd | grep "sha512sum /dev/zero" | grep "grep" -v | awk '{print $1}')
    if [ ! -z "$pid" ]; then
        echo "$pid" | xargs kill -9
    fi
}

function stop
{
    local pid
    pid=$(ps -eo pid,cmd | grep "sha512sum /dev/zero" | grep "grep" -v | awk '{print $1}')
    if [ ! -z "$pid" ]; then
        echo "$pid" | xargs kill -9
    fi
    pid=$(ps -eo pid,cmd | grep "pcpu.*start" | grep "grep" -v | awk '{print $1}')
    if [ ! -z "$pid" ]; then
        echo "$pid" | xargs kill -9
    fi
}

function show
{
    local interval_time
    interval_time=$1
    if [ "$interval_time" = "" ];then
        echo "当前cpu使用率: $(get_pcpu)%"
        exit 0
    fi
    is_digit "$interval_time"
    if [ $? -eq 0 ];then
        echo "Error: parameter interval_time is not a number"
        help
        exit 1
    fi

    while true
    do
        echo "当前cpu使用率: $(get_pcpu)%"
        sleep "$interval_time"
    done
}

case $1 in
    start)
        start $2 $3 $4 $5
    ;;
    stop)
        stop
    ;;
    show)
        show $2
    ;;
    help)
        help
    ;;
    *)
        echo "Error: invalid operation: $1"
        help
        exit 1
    ;;
esac